home *** CD-ROM | disk | FTP | other *** search
/ PC-X 1997 October / pcx14_9710.iso / swag / delphi.swg / 0071_Query By Form for DbGrid components in D.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-11-24  |  8.6 KB  |  262 lines

  1. {
  2. Here is a Delphi unit for a modal dialog to support Query By Form
  3. (QBF) for DbGrid components which receive data from Table components
  4. (not Query components).
  5.  
  6. The lack of this as a built-in feature makes it harder for Delphi to
  7. compete with more resource-intensive tools like Oracle Forms.
  8. This unit is not as powerful as the built-in QBF features of Oracle
  9. Forms, but it does fill a significant gap in functionality.
  10.  
  11. Note that the unit is copyrighted, as required by Borland's license,
  12. and as desired by me to retain credit for its development.
  13. Note that the copyright terms allow free use for any purpose.
  14.  
  15. }
  16.  
  17. unit Db_QBF;  { Database Query By Form -- Version 19950731 }
  18.  
  19. { Copyright 1995 by Rick Rutt.
  20.   This work may be used, copied, or distributed by anyone for any purpose,
  21.   provided all copies retain this copyright notice,
  22.   and provided no fee is charged for the contents of this work.
  23.   The author grants permission to anyone to create a derivative work,
  24.   provided each derivative work contains a copyright notice and the notice
  25.   "Portions of this work are based on Db_QBF.PAS as written by Rick Rutt."
  26. }
  27.  
  28. { This unit provides a basic but effective Query By Form service
  29.   for database access applications written using Borland Delphi.
  30.   This unit also provides a similar Sort By Form service.
  31.  
  32.   The Query By Form service displays a modal dialog box with a StringGrid
  33.   of searchable fields, taken from the calling DbGrid.  The user may
  34.   enter an exact search value for any number of fields, and may use
  35.   drag and drop to rearrange the sort order of the fields.
  36.   (Only the fields that contain search values are relevant to the sort.)
  37.   When the user clicks the dialog's OK button, this unit modifies the
  38.   calling DbGrid's IndexFieldNames property, applies a search range
  39.   (of exact values), and refreshes the data.
  40.   If the user leaves all search values empty, this unit clears the
  41.   calling DbGrid's IndexFieldNames property, clears the search range,
  42.   and refreshes the data.
  43.  
  44.   The Sort By Form service works in a similar manner, except that it
  45.   does not accept search values from the user.  The user drags and drops
  46.   the field sort order, then clicks the OK button.  This unit modifies
  47.   the calling DbGrid's IndexFieldNames property, clears the search range,
  48.   and refreshes the data.
  49. }
  50.  
  51. { Create the corresponding dialog form using the New Form action,
  52.   selecting a Standard Dialog Box.  Place a StringGrid on the form
  53.   (as found in the Additional tab of the component toolbar.
  54.   Set the StringGrid's Height to 161 and its Width to 305.
  55.   Finally, replace the new form's .PAS source with this unit.
  56. }
  57.  
  58. interface
  59.  
  60. uses WinTypes, WinProcs, Classes, Graphics, Forms, Controls, Buttons,
  61.   StdCtrls, ExtCtrls, Grids, DBGrids;
  62.  
  63. { The following two procedures provide the mechanism for accessing
  64.   the services of this unit.
  65.  
  66.   Have a button or menu item on the calling form call one of these
  67.   procedures, passing the DbGrid as the argument.  (Remember to add
  68.   "uses Db_QBF;" to the calling form's implementation section.)
  69.  
  70.   Restriction:  The DbGrid must reference a DataSource that, in turn,
  71.   references a DataSet that is a Table.  This unit does not support
  72.   a DataSet that is a Query, since it has no IndexFieldNames property.
  73. }
  74.  
  75. procedure QueryByForm(grid: TDbGrid);
  76.  
  77. procedure SortByForm(grid: TDbGrid);
  78.  
  79. { The following section is managed by the Delphi environment. }
  80.  
  81. type
  82.   TdlgQBF = class(TForm)
  83.     OKBtn: TBitBtn;
  84.     CancelBtn: TBitBtn;
  85.     HelpBtn: TBitBtn;
  86.     gridQBF: TStringGrid;
  87.     procedure OKBtnClick(Sender: TObject);
  88.     procedure CancelBtnClick(Sender: TObject);
  89.   private
  90.     { Private declarations }
  91.   public
  92.     { Public declarations }
  93.   end;
  94.  
  95. var
  96.   dlgQBF: TdlgQBF;
  97.  
  98. implementation
  99.  
  100. { The following section is managed by the programmer,
  101.   with assistance from the Delphi environment. }
  102.  
  103. uses Dialogs, Db, DbTables;
  104.  
  105. {$R *.DFM}
  106.  
  107. const
  108.   qbfRowHeight = 16;
  109.   qbfColWidth  = 150;
  110.  
  111.   qbfFieldLabel = '<<Field>>';
  112.   qbfValueLabel = '<<Value>>';
  113.  
  114.   qbfQueryCaption = 'Query for Table ';
  115.   qbfSortCaption  = 'Sort Order for Table ';
  116.  
  117. var
  118.   { Remember some things for use by the QBF dialog's OK button. }
  119.   CallingGrid: TDbGrid;
  120.   CallingMode: (modeQuery, modeSort);
  121.  
  122. procedure SetupAndShowForm;  { Called by the two exported procedures }
  123. var
  124.   i, j, n: integer;
  125.   tbl: TTable;
  126.   f: TField;
  127. begin
  128.   n := CallingGrid.FieldCount;
  129.   if n <= 0 then begin { Exceptions may be raised instead of showing messages }
  130.     MessageDlg(
  131.         'Db_QBF unit called for a DbGrid without any Fields',
  132.         mtWarning, [mbOK], 0);
  133.   end else if CallingGrid.DataSource = NIL then begin
  134.     MessageDlg(
  135.         'Db_QBF unit called for a DbGrid without a DataSource',
  136.         mtWarning, [mbOK], 0);
  137.   end else if CallingGrid.DataSource.DataSet = NIL then begin
  138.     MessageDlg(
  139.         'Db_QBF unit called for a DbGrid with a DataSource without a DataSet',
  140.         mtWarning, [mbOK], 0);
  141.   end else if not (CallingGrid.DataSource.DataSet is TTable) then begin
  142.     MessageDlg(
  143.         'Db_QBF unit called for a DbGrid with a DataSource that is not a Table',
  144.         mtWarning, [mbOK], 0);
  145.   end else with dlgQBF.gridQBF do begin
  146.     { These properties can also be set once at design time }
  147.     DefaultRowHeight := qbfRowHeight;
  148.     Scrollbars := ssVertical;
  149.     ColCount := 2;  { Even the Sort service needs a dummy second column }
  150.  
  151.     { These properties must be set at run time }
  152.     RowCount := Succ(n);
  153.     Cells[0,0] := qbfFieldLabel;
  154.     Options := Options + [goRowMoving];
  155.  
  156.     tbl := TTable(CallingGrid.DataSource.DataSet);
  157.  
  158.     if CallingMode = modeQuery then begin
  159.       dlgQBF.Caption := qbfQueryCaption + tbl.TableName;
  160.       Cells[1,0] := qbfValueLabel;
  161.       Options := Options + [goEditing];  { Allow user to enter values }
  162.       DefaultColWidth  := qbfColWidth;
  163.     end else begin
  164.       dlgQBF.Caption := qbfSortCaption + tbl.TableName;
  165.       Cells[1,0] := '';  { Dummy "value" column to allow fixed "field" column }
  166.       Options := Options - [goEditing];  { User just reorders the rows }
  167.       DefaultColWidth  := (2 * qbfColWidth);  { Shove aside dummy 2nd column }
  168.     end;
  169.  
  170.     j := 0;  { Actual number of fields shown to user }
  171.     for i := 1 to n do begin
  172.       f := CallingGrid.Fields[Pred(i)];
  173.       if f.DataType in [ftBlob,ftBytes,ftGraphic,ftMemo,ftUnknown,ftVarBytes]
  174.           then  RowCount := Pred(RowCount)  { Ignore unsearchable fields }
  175.       else begin
  176.         Inc(j);
  177.         Cells[0,j] := f.FieldName;
  178.         Cells[1,j] := '';  { Empty search value }
  179.       end;
  180.     end;
  181.  
  182.     dlgQBF.HelpBtn.Visible := False;  { We haven't implemented Help }
  183.     dlgQBF.ShowModal;
  184.   end;  { with dlgQBF.gridQBF }
  185. end;
  186.  
  187. procedure QueryByForm(Grid: TDbGrid);
  188. begin
  189.   CallingGrid := Grid;  { Save for use by OK button }
  190.   CallingMode := modeQuery;
  191.   SetupAndShowForm;
  192. end;
  193.  
  194. procedure SortByForm(Grid: TDbGrid);
  195. begin
  196.   CallingGrid := Grid;  { Save for use by OK button }
  197.   CallingMode := modeSort;
  198.   SetupAndShowForm;
  199. end;
  200.  
  201. procedure TdlgQBF.CancelBtnClick(Sender: TObject);
  202. begin
  203.   { Just dismiss the dialog, without making changes to the calling grid. }
  204.   dlgQBF.Hide;
  205. end;
  206.  
  207. procedure TdlgQBF.OKBtnClick(Sender: TObject);
  208. var
  209.   flds, sep, val: string;
  210.   i, n, nfld: integer;
  211. begin
  212.   flds := '';  { List of fields separated by ';'.}
  213.   sep  := '';  { Becomes ';' after the 1st field is appended. }
  214.   nfld := 0;   { Number of fields in the list. }
  215.  
  216.   with dlgQBF.gridQBF do begin
  217.     n := Pred(RowCount);
  218.     if n > 0 then for i := 1 to n do begin
  219.       val := Cells[1,i];  { The user-entered search value (if any) }
  220.       if (CallingMode = modeSort)
  221.       or (val <> '') then begin
  222.         flds := flds + sep + Cells[0,i];
  223.         sep  := ';';
  224.         nfld := Succ(nfld);
  225.       end;
  226.     end;
  227.  
  228.     with CallingGrid.DataSource.DataSet as TTable do begin
  229.       IndexFieldNames := flds;
  230.       if (CallingMode = modeSort)
  231.       or (flds = '') then begin
  232.         CancelRange;
  233.       end else begin
  234.         SetRangeStart;
  235.         for i := 1 to n do begin
  236.           val := Cells[1,i];
  237.           if val <> '' then begin
  238.             FieldByName(Cells[0,i]).AsString := val;
  239.           end;
  240.         end;
  241.  
  242.         SetRangeEnd;  { Set range end to match range start }
  243.         for i := 1 to n do begin
  244.           val := Cells[1,i];
  245.           if val <> '' then begin
  246.             FieldByName(Cells[0,i]).AsString := val;
  247.           end;
  248.         end;
  249.  
  250.         ApplyRange;
  251.       end;
  252.  
  253.       Refresh;
  254.     end;  { with CallingGrid.DataSource.DataSet }
  255.   end;  { with dlgQBF.gridQBF }
  256.  
  257.   dlgQBF.Hide;
  258. end;
  259.  
  260. end.
  261.  
  262.